package com.zhichat.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.zhichat.dao.ApplyInfoDao;
import com.zhichat.dao.ContactInfoDao;
import com.zhichat.dao.GroupInfoDao;
import com.zhichat.dao.UserInfoDao;
import com.zhichat.entity.ApplyInfoEntity;
import com.zhichat.entity.ContactInfoEntity;
import com.zhichat.entity.GroupInfoEntity;
import com.zhichat.entity.UserInfoEntity;
import com.zhichat.infrastructure.Enums.ApplyStatusEnum;
import com.zhichat.infrastructure.Enums.ApplyTypeEnum;
import com.zhichat.infrastructure.Enums.ContactStatusEnum;
import com.zhichat.infrastructure.Enums.ContactTypeEnum;
import com.zhichat.infrastructure.constants.Constants;
import com.zhichat.infrastructure.exception.http.CommonException;
import com.zhichat.infrastructure.util.ThreadLocalCache;
import com.zhichat.service.ApplyInfoService;
import com.zhichat.service.ContactInfoService;
import com.zhichat.web.api.PageUtils;
import com.zhichat.web.dto.ApplyGeneDTO;
import com.zhichat.web.dto.dao.ApplyInfoListQuery;
import com.zhichat.web.vo.ApplyInfoVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@Service
@AllArgsConstructor
public class ApplyInfoServiceImpl extends ServiceImpl<ApplyInfoDao, ApplyInfoEntity> implements ApplyInfoService {

    private final ContactInfoDao contactInfoDao;
    private final ContactInfoService contactInfoService;
    private final UserInfoDao userInfoDao;
    private final GroupInfoDao groupInfoDao;

    @Override
    public PageUtils<ApplyInfoVO> applyList(Integer pageNumber) {
        if (0 == pageNumber) {
            pageNumber = 1;
        }
        Long receiveId = ThreadLocalCache.getUserId();
        // 查询申请列表
        ApplyInfoListQuery query = new ApplyInfoListQuery(receiveId, Constants.PAGE_SIZE, pageNumber);
        List<ApplyInfoVO> dataList = baseMapper.queryApplyInfoList(query);
        // 查询总条数
        LambdaQueryWrapper<ApplyInfoEntity> queryWrapper = Wrappers.lambdaQuery(ApplyInfoEntity.class);
        queryWrapper.eq(ApplyInfoEntity::getReceiveId, receiveId);
        Integer totalCount = Math.toIntExact(baseMapper.selectCount(queryWrapper));
        // 返回数据
        PageUtils<ApplyInfoVO> pageData = new PageUtils<>(dataList,
                totalCount,
                Constants.PAGE_SIZE,
                pageNumber);
        return pageData;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean dealApply(ApplyGeneDTO dto) {
        Long applyInfoId = dto.getApplyInfoId();
        Integer status = dto.getStatus();
        // 校验 数据
        if (Objects.equals(ApplyStatusEnum.APPLYING.getCode(), status) || ApplyStatusEnum.getByCode(status) == null) {
            throw CommonException.PARAMETER_COMMON_EXCEPTION;
        }
        LambdaQueryWrapper<ApplyInfoEntity> queryWrapper = Wrappers.lambdaQuery(ApplyInfoEntity.class);
        queryWrapper.eq(ApplyInfoEntity::getId, applyInfoId);
        ApplyInfoEntity applyInfoEntity = baseMapper.selectOne(queryWrapper);
        if (Objects.isNull(applyInfoEntity) || !Objects.equals(ApplyStatusEnum.APPLYING.getCode(), applyInfoEntity.getStatus())
                || !Objects.equals(applyInfoEntity.getReceiveId(), ThreadLocalCache.getUserId())) {
            throw CommonException.PARAMETER_COMMON_EXCEPTION;
        }
        Long receiveId = ThreadLocalCache.getUserId();
        Integer contactType = applyInfoEntity.getContactType();
        Long applyId = applyInfoEntity.getApplyId();
        Long contactId = applyInfoEntity.getContactId();
        String applyMessage = applyInfoEntity.getApplyMessage();
        LocalDateTime curDate = LocalDateTime.now();
        // 修改 这条待处理的数据 -> 改成 传入的 status
        LambdaUpdateWrapper<ApplyInfoEntity> updateWrapper = Wrappers.lambdaUpdate(ApplyInfoEntity.class);
        updateWrapper.eq(ApplyInfoEntity::getId, applyInfoId)
                .eq(ApplyInfoEntity::getStatus, ApplyStatusEnum.APPLYING.getCode())
                .set(ApplyInfoEntity::getStatus, status)
                .set(ApplyInfoEntity::getLastApplyTime, DateUtil.date(curDate).getTime());
        if (0 == baseMapper.update(null, updateWrapper)) {
            throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
        }
        if (Objects.equals(ApplyTypeEnum.USER.getCode(), contactType)) {
            // 有可能 它也申请我加好友，我也申请它加好友了，所以这里，要一并处理【直接设置成已失效】
            LambdaQueryWrapper<ApplyInfoEntity> tmpApplyQuery = Wrappers.lambdaQuery(ApplyInfoEntity.class);
            tmpApplyQuery.select(ApplyInfoEntity::getId)
                    .eq(ApplyInfoEntity::getApplyId, receiveId)
                    .eq(ApplyInfoEntity::getStatus, ApplyStatusEnum.APPLYING.getCode())
                    .eq(ApplyInfoEntity::getContactId, applyId)
                    .last(" for update");
            ApplyInfoEntity tmpApplyInfoEntity = baseMapper.selectOne(tmpApplyQuery);
            if (Objects.nonNull(tmpApplyInfoEntity)) {
                LambdaUpdateWrapper<ApplyInfoEntity> tmpApplyWrapper = Wrappers.lambdaUpdate(ApplyInfoEntity.class);
                tmpApplyWrapper.eq(ApplyInfoEntity::getId, tmpApplyInfoEntity.getId())
                        .eq(ApplyInfoEntity::getStatus, ApplyStatusEnum.APPLYING.getCode())
                        .set(ApplyInfoEntity::getStatus, ApplyStatusEnum.EXPIRED.getCode())
                        .set(ApplyInfoEntity::getLastApplyTime, DateUtil.date(curDate).getTime());
                if (0 == baseMapper.update(null, tmpApplyWrapper)) {
                    throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
                }
            }
            // 如果是拉黑，则需要在联系人表添加 已拉黑和被拉黑信息（删除不用管，因为可以继续再次申请）
            if (Objects.equals(ApplyStatusEnum.BLACKED.getCode(), status)) {
                // 查看联系人列表是否已有该 联系人信息
                LambdaQueryWrapper<ContactInfoEntity> contactWrapper = Wrappers.lambdaQuery(ContactInfoEntity.class);
                contactWrapper.select(ContactInfoEntity::getUserId, ContactInfoEntity::getContactId)
                        .and(wrapper -> wrapper.eq(ContactInfoEntity::getUserId, receiveId)
                                .eq(ContactInfoEntity::getContactId, applyId))
                        .or(wrapper -> wrapper.eq(ContactInfoEntity::getUserId, applyId)
                                .eq(ContactInfoEntity::getContactId, receiveId));
                List<ContactInfoEntity> checkList = contactInfoDao.selectList(contactWrapper);
                if (CollectionUtils.isEmpty(checkList)) {
                    ContactInfoEntity insertEntity = new ContactInfoEntity();
                    insertEntity.setUserId(receiveId)
                            .setContactId(applyId)
                            .setContactType(ContactTypeEnum.USER.getCode())
                            .setLastUpdateTime(LocalDateTimeUtil.toEpochMilli(curDate))
                            .setStatus(ContactStatusEnum.BLACKLIST_FRIEND.getCode());
                    ContactInfoEntity insertEntity1 = new ContactInfoEntity();
                    insertEntity1.setUserId(applyId)
                            .setContactId(receiveId)
                            .setContactType(ContactTypeEnum.USER.getCode())
                            .setLastUpdateTime(LocalDateTimeUtil.toEpochMilli(curDate))
                            .setStatus(ContactStatusEnum.BLACKLISTED_BY_FRIEND.getCode());
                    contactInfoDao.bulk(Lists.newArrayList(insertEntity, insertEntity1));
                } else {
                    List<ContactInfoEntity> dataList = Lists.newArrayList();
                    Optional<ContactInfoEntity> first = checkList.stream().filter(x -> x.getUserId().equals(receiveId)).findFirst();
                    Optional<ContactInfoEntity> first1 = checkList.stream().filter(x -> x.getUserId().equals(applyId)).findFirst();
                    if (first.isPresent()) {
                        ContactInfoEntity contactInfoEntity = first.get();
                        contactInfoEntity.setLastUpdateTime(LocalDateTimeUtil.toEpochMilli(curDate))
                                .setStatus(ContactStatusEnum.BLACKLIST_FRIEND.getCode());
                        contactInfoDao.updateById(contactInfoEntity);
                    } else {
                        dataList.add(new ContactInfoEntity()
                                .setUserId(receiveId)
                                .setContactId(applyId)
                                .setContactType(ContactTypeEnum.USER.getCode())
                                .setLastUpdateTime(LocalDateTimeUtil.toEpochMilli(curDate))
                                .setStatus(ContactStatusEnum.BLACKLIST_FRIEND.getCode()));
                    }
                    if (first1.isPresent()) {
                        ContactInfoEntity contactInfoEntity = first1.get();
                        contactInfoEntity.setLastUpdateTime(LocalDateTimeUtil.toEpochMilli(curDate))
                                .setStatus(ContactStatusEnum.BLACKLISTED_BY_FRIEND.getCode());
                        contactInfoDao.updateById(contactInfoEntity);
                    } else {
                        dataList.add(new ContactInfoEntity()
                                .setUserId(applyId)
                                .setContactId(receiveId)
                                .setContactType(ContactTypeEnum.USER.getCode())
                                .setLastUpdateTime(LocalDateTimeUtil.toEpochMilli(curDate))
                                .setStatus(ContactStatusEnum.BLACKLISTED_BY_FRIEND.getCode()));
                    }
                    if (!CollectionUtils.isEmpty(dataList)) {
                        contactInfoDao.bulk(dataList);
                    }
                }
            }
        }
        // 如果传入的状态是 ： 同意
        if (Objects.equals(ApplyStatusEnum.APPROVED.getCode(), status)) {
            Document paramDoc = new Document();
            paramDoc.put("contactNickname", ThreadLocalCache.getUserToken().getNickname());
            LambdaQueryWrapper<UserInfoEntity> userInfoQuery = Wrappers.lambdaQuery(UserInfoEntity.class);
            userInfoQuery.select(UserInfoEntity::getNickname)
                    .eq(UserInfoEntity::getId, applyId);
            UserInfoEntity userInfoEntity = userInfoDao.selectOne(userInfoQuery);
            if (Objects.equals(ApplyTypeEnum.GROUP.getCode(), contactType)) {
                LambdaQueryWrapper<GroupInfoEntity> groupInfoQuery = Wrappers.lambdaQuery(GroupInfoEntity.class);
                groupInfoQuery.select(GroupInfoEntity::getGroupId, GroupInfoEntity::getGroupName)
                        .eq(GroupInfoEntity::getGroupId, contactId);
                GroupInfoEntity groupInfoEntity = groupInfoDao.selectOne(groupInfoQuery);
                paramDoc.put("contactNickname", groupInfoEntity.getGroupName());
            }
            paramDoc.put("applyId", applyId);
            paramDoc.put("applyNickname", userInfoEntity.getNickname());
            paramDoc.put("receiveId", receiveId);
            paramDoc.put("contactId", contactId);
            paramDoc.put("contactType", contactType);
            paramDoc.put("applyMsg", applyMessage);
            paramDoc.put("curDate", curDate);
            contactInfoService.addContactInfo(paramDoc);
        }
        return true;
    }
}